Conversation
Defines a portable rule the four oxc editor extensions
(oxc-vscode, oxc-zed, oxc-intellij-plugin, coc-oxc) use to decide
whether to launch `vp lint --lsp` / `vp fmt --lsp` instead of plain
oxlint / oxfmt, and to resolve which executable to spawn.
Core algorithm (two phases, both bounded by the workspace root):
1. Phase 1 — find the package.json that DIRECTLY declares vite-plus
in dependencies or devDependencies. A transitively hoisted
`node_modules/vite-plus/` does not count.
2. Phase 2 — walk up from the declaring ancestor looking for a real
`node_modules/vite-plus/bin/vp` with a sibling `package.json` that
parses and has `name === "vite-plus"`.
Result is a tri-state: `null` (not Vite+), `{ root, vpPath }`
(Vite+ and runnable), or `{ root }` (declared but not yet installed —
editors fall back to plain oxlint/oxfmt and never launch a bare vp).
Distribution: for the Node-capable extensions (oxc-vscode, coc-oxc)
the detector ships as a shared bundled-devDependency package
(@voidzero-dev/detect-vite-plus, name TBD) at
`packages/detect-vite-plus/`. oxc-zed (Rust) and
oxc-intellij-plugin (Kotlin) port the same algorithm against the
shared conformance fixtures.
The RFC also documents:
- The four extensions' existing bin-resolution chains with code
excerpts and file:line citations.
- A Mermaid flowchart of the two-phase algorithm for cross-language
porters.
- The workspace-root marker set (`pnpm-workspace.yaml`,
`package.json#workspaces`, `lerna.json`) and a known parity gap
with vite-task that this RFC does not block on.
- Per-extension migration plans and a conformance fixture table that
pins down behaviour across every implementation.
Refs #1557
✅ Deploy Preview for viteplus-preview canceled.
|
… isn't .vp-root was a fabricated example. Replace with .vite-hooks, which is the real vite-plus hooks directory (packages/cli/src/config/hooks.ts:67) and a more useful illustration of "incidental vite-plus artifact that must not stop the walk-up." Refs #1557
The detector now reads node_modules/vite-plus/package.json#version alongside name validation and returns it in DetectResult as vpVersion. Editors compare against MIN_VP_VERSION_FOR_LSP (a constant exported by the shared detector package, filled in when #1557's wrapper removal lands) to choose between launching `vp lint --lsp` and falling through to the legacy bin/oxlint wrapper chain shipped by older vite-plus versions. Three benefits: - Smooth rollout: workspaces pinned to older vite-plus keep working via the existing wrapper, no breakage on upgrade of the editor extension alone. - Upgrade hint: editors can surface "upgrade vite-plus to enable native LSP" when the installed version is too old. - Forward compatibility: future LSP-only features can raise the threshold by bumping the detector package, not by changing every consumer. Changes: - DetectResult gains optional vpVersion (set whenever vpPath is set). - resolveVpAt() rejects installs whose package.json has no string version, treating them as orphan. - Public API adds MIN_VP_VERSION_FOR_LSP constant and supportsLsp() helper for both consumers to use. - Per-extension migration plan gains a fourth branch for the "installed but version too old" case. - New conformance fixtures: installed-but-version-too-old, installed-no-version-field. - New open question: the concrete value of MIN_VP_VERSION_FOR_LSP (TBD until #1557 ships).
826 lines → 302 lines. Reviewer flagged repetition and pushed back on the version-gating mechanism. Changes: - Drop MIN_VP_VERSION_FOR_LSP / supportsLsp / vpVersion entirely. Editors just attempt `vp lint --lsp`; if it fails on an old vp, the editor surfaces an upgrade hint at that point. - Change "declared but not installed" UX: surface an install hint instead of silently falling back to plain oxlint. The reviewer is right that plain oxlint without VP_VERSION isn't Vite+-aware anyway, so silent fallback misleads more than it helps. - Heavy trim of repetition: drop "Insight", drop the long bin-resolution code excerpts (kept brief file:line refs), fold "Why this rule" into the rule section, collapse the Decisions section, drop "Downstream coordination" (overlapped with the migration plan), drop the "Verification plan" subheading. - Move "publish as a shared npm package?" from a locked Decision to an Open Question — the reviewer asked us to make the call; making it visibly open instead of locked invites the reviewer to weigh in. - Shrink the conformance fixture table: drop entries that document non-features (global-vp-on-path, user-binpath-override) now that the rule plainly says we don't check $PATH or user settings, and drop the version-related fixtures.
| `dependencies` or `devDependencies`. A `node_modules/vite-plus/` | ||
| directory on its own does not qualify — that could be a transitive | ||
| install hoisted from an unrelated dependency tree. |
There was a problem hiding this comment.
A `node_modules/vite-plus/` directory on its own does not qualify — that could be a transitive install hoisted from an unrelated dependency tree.
I am not sure if vite-plus will ever be a dependency of another package. My naive brain does not like this.
VS Code Extension searched for package.json and tries to find node_modules/.bin/xyz.
Opening the package-file, transforming it to JSON, and checking its properties, will be done by every package.json it will find.
On a monorepo this could be expensive. 🤔
| Both phases stop AT the workspace root and never cross into its | ||
| parent. The walk-up bound is what prevents a nested checkout from | ||
| inheriting an unrelated parent's Vite+ install. |
There was a problem hiding this comment.
Some users will open only a sub-package of a monorepo. Vite-plus from the root will not be detected.
Note: VS Code Extension does search outside the root (beside require.resolve), because mostly they are using Nested Multi Root Workspaces. But we should make sure setups like this will detect vite-plus
|
|
||
| ### Workspace root markers | ||
|
|
||
| A directory is a workspace root if any of the following is true: |
There was a problem hiding this comment.
Workspace roots are managed by the IDE itself. I do not think we should implement something new. (At least for VS Code).
Specially because users can add/remove workspaces roots from a single IDE session:
https://code.visualstudio.com/docs/editing/workspaces/multi-root-workspaces
For what is the workspace root marker useful?
| `<vite-plus>/bin/oxlint` to `<vite-plus>/bin/vp`, update launch | ||
| args. | ||
|
|
||
| ## Conformance fixtures |
There was a problem hiding this comment.
What happens for workspaces where the root package.json does include oxlint, and only a sub-package includes vite-plus?
Should we prefer the vite-plus from the sub-package, even if other packages will use the roots oxlint?
Maybe related: oxc-project/oxc-vscode#145
| 1. **Publish the detector as a shared npm package?** The current | ||
| proposal is `@voidzero-dev/detect-vite-plus` at | ||
| `packages/detect-vite-plus/`, consumed as a bundled devDependency | ||
| by `oxc-vscode` and `coc-oxc`. The alternative is to let each | ||
| Node-capable extension copy the ~50-line snippet directly. | ||
| Decision deferred to the maintainers. |
There was a problem hiding this comment.
The package makes sense for me. But I am not sure if this will be useful for other editors as they don't have JS runtime and needs to recreate it anyway by hand.
|
|
||
| /** `bin/vp` exists AND the sibling package.json identifies as vite-plus. */ | ||
| function resolveVpAt(dir: string): string | null { | ||
| const vpPath = join(dir, 'node_modules', 'vite-plus', 'bin', 'vp'); |
There was a problem hiding this comment.
Normally we search for node_modules/.bin/oxlint and not node_modules/oxlint/bin/oxlint.
Is there a good reason to not target the .bin wrapper?
| - `$PATH`, user's global `node_modules`, or | ||
| `oxc.<tool>.binPath` settings (the last is for oxlint/oxfmt, not | ||
| `vp`). |
There was a problem hiding this comment.
I would like to search for global node_modules and $PATH variable too.
Users want a global editor formatter, which they can use without forcing the repo-dependency.
VP-Users needs to know that oxfmt is used and manual install it globally.
| | `bin-vp-orphan` | Declared in root `package.json`, but `node_modules/vite-plus/` is broken (missing `package.json`, wrong `name`, or unparseable) | `{ root: "<repo>" }` — install rejected as orphan | | ||
| | `parent-vite-plus-nested-repo` | Outer dir declares + installs `vite-plus`; inner subdir is its own workspace root and does not | From inside the nested workspace: `null` | | ||
| | `plain-non-vite-plus` | A normal Node project, no `vite-plus` anywhere | `null` | | ||
| | `yarn4-pnp` | Berry/PnP, no `node_modules`, root `package.json` declares `vite-plus` | `{ root: "<repo>" }` — install hint | |
There was a problem hiding this comment.
No Yarn PnP support for vp? For VSCode oxlint and oxfmt it is supported:
https://github.com/oxc-project/oxc-vscode/blob/aeeb69c6a7990738d31e53dd21b73dce9776f63c/client/findBinary.ts#L171-L196
Summary
Draft RFC defining how the four oxc editor extensions —
oxc-vscode,oxc-zed,oxc-intellij-plugin,coc-oxc— determine whether a workspace is a Vite+ project and whichvpexecutable to spawn for--lsp. This is the prerequisite identified in #1557 for removing the per-packagebin/oxlint/bin/oxfmtwrappers.Core rule
A workspace is Vite+ iff some walked-up
package.jsondirectly declaresvite-plusindependenciesordevDependencies(bounded by the workspace root). The runnablevpbinary is resolved separately, also bounded by the workspace root, and validated against a realvite-pluspackage (name === "vite-plus").Detector returns a tri-state:
null— not Vite+; editor uses plain oxlint/oxfmt.{ root, vpPath }— Vite+ and runnable; editor launchesvp lint --lsp/vp fmt --lsp.{ root }— declared but not yet installed (fresh clone, Berry PnP, broken install); editor falls back to plain oxlint/oxfmt and never spawns a barevp.A transitively hoisted
node_modules/vite-plus/, a globalvp, avpon\$PATH, and a configuredoxc.<tool>.binPathall returnnullby construction.Distribution
oxc-vscodeandcoc-oxcconsume a shared bundled-devDependency npm package (proposed@voidzero-dev/detect-vite-plus) atpackages/detect-vite-plus/.oxc-zed(Rust/WASM) andoxc-intellij-plugin(Kotlin) port the same algorithm against the shared conformance fixtures inside this RFC.Status
Draft for discussion. Open points called out in the RFC:
vite-task(recognized as a known follow-up; deliberately not blocked on).Refs #1557